﻿using FB.Data;
using FB.Enums;
 
//using FB.Data.Models;
using FB.Providers.EmployeeInfo;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace FB.Providers
{
    public class EFEmployeeInfoProvider : AspNetEmployeeInfoProvider
    {
        string _ConnString = string.Empty;
        EMPDbContext _db = null;

        public string connectionStringName { get; set; }


        public override void Initialize(string name, NameValueCollection config)
        {
            base.Initialize(name, config);

            #region initialize custom attributes

            this.connectionStringName = config["connectionStringName"];

            #endregion

            if (string.IsNullOrEmpty(this.connectionStringName))
                throw new ConfigurationErrorsException("connectionStringName must be set to the appropriate value");

            if (ConfigurationManager.ConnectionStrings[this.connectionStringName] == null)
                throw new ConfigurationErrorsException("connection string not found.");

            _ConnString = ConfigurationManager.ConnectionStrings[this.connectionStringName].ConnectionString;
        }

        /*
        #region Company Management

        public override Company GetCompany(string COMCode)
        {
            return Get<Company>(w => w.COMCode == COMCode, "ParentCompany");
        }

        public override List<EmployeeInfo.Company> GetAllCompanies()
        {
            return GetAll<Company>(null,"ParentCompany").ToList();
        }

        public override List<EmployeeInfo.Company> FindCompanies(Expression<Func<EmployeeInfo.Company, bool>> filter = null)
        {
            return GetAll(filter, "ParentCompany").ToList();
        }



        public override EmployeeInfo.Company CreateCompany(EmployeeInfo.Company company)
        {
            return Create(company);
        }


        public override void UpdateCompany(EmployeeInfo.Company company)
        {
            Update(company);
        }


        public override void DeleteCompany(string COMCode)
        {
            Delete<Company>(w => w.COMCode == COMCode);
        }

        public override List<Company> FindCompanies(Expression<Func<Company, bool>> filter, Func<IQueryable<Company>, IOrderedQueryable<Company>> orderBy, int pageIndex, int pageSize, out int totalRecords)
        {
            return GetWithPaging(filter, orderBy, pageIndex, pageSize, out totalRecords, "ParentCompany").ToList();
        }
        #endregion


        #region Department Management


        public override Department GetDepartment(string DEPTCode, string includeProperties = "")
        {
            return Get<Department>(w => w.DEPTCode == DEPTCode, "ParentDepartment,Company");
        }

        public override List<Department> GetAllDepartments()
        {
            return GetAll<Department>(null, "ParentDepartment,Company").ToList();
        }

        public override List<Department> FindDepartments(Expression<Func<Department, bool>> filter = null, string includeProperties ="")
        {
            return GetAll(filter, "ParentDepartment,Company").ToList();        }


        public override Department CreateDepartment(Department department)
        {
            return Create(department);
        }


        public override void UpdateDepartment(Department department)
        {
            Update(department);
        }


        public override void DeleteDepartment(string DEPTCode)
        {
            Delete<Department>(w => w.DEPTCode == DEPTCode);
        }

        public override List<Department> FindDepartments(Expression<Func<Department, bool>> filter, Func<IQueryable<Department>, IOrderedQueryable<Department>> orderBy, int pageIndex, int pageSize, out int totalRecords)
        {
            return GetWithPaging(filter, orderBy, pageIndex, pageSize, out totalRecords, "ParentDepartment,Company").ToList();
        }
        #endregion


        #region Position Management


        public override Position GetPosition(string POSCode)
        {
            return Get<Position>(w => w.POSCode == POSCode, "ParentPosition");
        }

        public override List<Position> GetAllPositions()
        {
            return GetAll<Position>(null, "ParentPosition").ToList();
        }

        public override List<Position> FindPositions(Expression<Func<Position, bool>> filter = null)
        {
            return GetAll(filter, "ParentPosition").ToList();
        }


        public override Position CreatePosition(Position position)
        {
            return Create(position);
        }


        public override void UpdatePosition(Position position)
        {
            Update(position);
        }


        public override void DeletePosition(string POSCode)
        {
            Delete<Position>(w => w.POSCode == POSCode);
        }
        public override List<Position> FindPositions(Expression<Func<Position, bool>> filter, Func<IQueryable<Position>, IOrderedQueryable<Position>> orderBy, int pageIndex, int pageSize, out int totalRecords)
        {
            return GetWithPaging(filter, orderBy, pageIndex, pageSize, out totalRecords).ToList();
        }

        #endregion


        #region Employee Management


        public override string GenerateEMPCode(string EMPType)
        {
            var code = string.Empty;

            var employeeType = Get<EmployeeType>(w => w.EMPType == EMPType, "Sequence");
            if (null != employeeType)
            {
                code = string.Format("{0}{1}", employeeType.EMPType, employeeType.Sequence.CurrentValue.ToString().PadLeft(6, '0'));
                employeeType.Sequence.CurrentValue = employeeType.Sequence.CurrentValue + 1;
                Update<Sequence>(employeeType.Sequence);
            }

            return code;

        }

        public override Employee GetEmployee(string EMPCode, string includeProperties = "")
        {
            return Get<Employee>(w => w.EMPCode == EMPCode, includeProperties);
        }

        public override List<Employee> GetAllEmployees(string includeProperties = "")
        {
            return GetAll<Employee>(includeProperties: includeProperties);
        }

        public override List<Employee> FindEmployees(Expression<Func<Employee, bool>> filter = null, string includeProperties = "")
        {
            return GetAll(filter, includeProperties);
        }

        public override List<Employee> FindEmployees(
            Expression<Func<Employee, bool>> filter,
            Func<IQueryable<Employee>, IOrderedQueryable<Employee>> orderBy,
            int pageIndex, int pageSize, out int totalRecords, string includeProperties = "")
        {
            return GetWithPaging(filter, orderBy, pageIndex, pageSize, out totalRecords, includeProperties).ToList();
        }

        public override bool CreateEmployee(Employee employee)
        {
            var affectedRow = 0;
            Create(employee, out affectedRow);
            return affectedRow > 0;
        }


        public override bool UpdateEmployee(Employee employee)
        {
            return Update(employee);
        }


        public override void DeleteEmployee(string EMPCode)
        {
            Delete<Employee>(w => w.EMPCode == EMPCode);
        }


        #endregion


        #region Employee Type Management


        public override EmployeeType GetEmployeeType(string EMPType)
        {
            return Get<EmployeeType>(w => w.EMPType == EMPType);
        }

        public override List<EmployeeType> GetAllEmployeeTypes()
        {
            return GetAll<EmployeeType>().ToList();
        }

        public override List<EmployeeType> FindEmployeeTypes(Expression<Func<EmployeeType, bool>> filter = null)
        {
            return GetAll(filter).ToList();
        }


        public override EmployeeType CreateEmployeeType(EmployeeType employeeType, uint initialSeqNumber = 0)
        {
            employeeType.Sequence = new Sequence { CurrentValue = initialSeqNumber };
            return Create(employeeType);
        }


        public override void UpdateEmployeeType(EmployeeType employeeType)
        {
            Update(employeeType);
        }


        public override void DeleteEmployeeType(string EMPType)
        {
            Delete<EmployeeType>(w => w.EMPType == EMPType);
        }
        public override List<EmployeeType> FindEmployeeTypes(Expression<Func<EmployeeType, bool>> filter, Func<IQueryable<EmployeeType>, IOrderedQueryable<EmployeeType>> orderBy, int pageIndex, int pageSize, out int totalRecords)
        {
            return GetWithPaging(filter, orderBy, pageIndex, pageSize, out totalRecords).ToList();
        }
        
        #endregion



        #region Team Management

        public override List<Team> FindTeams(Expression<Func<Team, bool>> filter, Func<IQueryable<Team>, IOrderedQueryable<Team>> orderBy, int pageIndex, int pageSize, out int totalRecords)
        {
            return GetWithPaging(filter, orderBy, pageIndex, pageSize, out totalRecords, "Department").ToList();
        }
        public override List<Team> FindTeams(IList<Expression<Func<Team, bool>>> filters, Func<IQueryable<Team>, IOrderedQueryable<Team>> orderBy, int pageIndex, int pageSize, out int totalRecords)
        {
            return GetWithPaging(filters, orderBy, pageIndex, pageSize, out totalRecords, "Department").ToList();
        }
        public override Team GetTeam(string TEAMCode)
        {
            return Get<Team>(w => w.TEAMCode == TEAMCode, "Department");
        }

        public override List<Team> GetAllTeams()
        {
            return GetAll<Team>(null, "Department").ToList();
        }

        public override List<Team> FindTeams(Expression<Func<Team, bool>> filter = null)
        {
            return GetAll(filter, "Department").ToList();
        }


        public override Team CreateTeam(Team team)
        {
            return Create(team);
        }


        public override void UpdateTeam(Team team)
        {
            Update(team);
        }


        public override void DeleteTeam(string TEAMCode)
        {
            Delete<Team>(w => w.TEAMCode == TEAMCode);
        }


        #endregion



























































        #region private methods

        Repository<EMPDbContext, TEntity> GetRepository<TEntity>() where TEntity : class , new()
        {
            if(null == _db) 
                _db = new EMPDbContext(this._ConnString);

            return new Repository<EMPDbContext, TEntity>(_db);
        }


        List<TEntity> GetWithPaging<TEntity>(
          IList<Expression<Func<TEntity, bool>>> filters,
          Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy,
          int pageIndex, int pageSize, out int totalRecords, string includeProperties = ""
          ) where TEntity : class , new()
        {
            using (var repos = new Repository<EMPDbContext, TEntity>(new EMPDbContext(this._ConnString)))
            {
                //var repos = GetRepository<TEntity>();
                var result = repos.GetEntities(filters, orderBy, includeProperties: includeProperties);
                totalRecords = result.Count();

                return result.Skip(pageSize * pageIndex).Take(pageSize).ToList();
            }
        }


        List<TEntity> GetWithPaging<TEntity>(
            Expression<Func<TEntity, bool>> filter,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy,
            int pageIndex, int pageSize, out int totalRecords, string includeProperties = ""
            ) where TEntity : class , new()
        {
            using (var repos = new Repository<EMPDbContext, TEntity>(new EMPDbContext(this._ConnString)))
            {
                //var repos = GetRepository<TEntity>();
                var result = repos.Get(filter, orderBy, includeProperties: includeProperties);
                totalRecords = result.Count();

                return result.Skip(pageSize * pageIndex).Take(pageSize).ToList();
            }
        }


        // generic create method
        TEntity Create<TEntity>(TEntity model) where TEntity : class , new()
        {
            int affectedRow = 0;
            return Create<TEntity>(model, out affectedRow);
        }


        TEntity Create<TEntity>(TEntity model, out int affectedRow) where TEntity : class , new()
        {
            using (var repos = new Repository<EMPDbContext, TEntity>(new EMPDbContext(this._ConnString)))
            {
                //var repos = GetRepository<TEntity>();
                var result = repos.Insert(model);
                affectedRow = repos.SaveChanges();
                return result;
            }
        }


        TEntity Get<TEntity>(Expression<Func<TEntity, bool>> filter = null, string includeProperties = "") where TEntity : class , new()
        {
            using (var repos = new Repository<EMPDbContext, TEntity>(new EMPDbContext(this._ConnString)))
            {
                //var repos = GetRepository<TEntity>();
                return repos.Get(filter, includeProperties: includeProperties).FirstOrDefault();
                //return repos.dbSet.FirstOrDefault<TEntity>(filter);
            }
        }


        // generic get all entities method
        List<TEntity> GetAll<TEntity>(Expression<Func<TEntity, bool>> filter = null, string includeProperties = "") where TEntity : class  , new()
        {
            using (var repos = new Repository<EMPDbContext, TEntity>(new EMPDbContext(this._ConnString)))
            {
                //var repos = GetRepository<TEntity>();
                return repos.Get(filter, includeProperties: includeProperties).ToList();
            }
        }


        // generic update method
        bool Update<TEntity>(TEntity model) where TEntity : class , new()
        {
            using (var repos = new Repository<EMPDbContext, TEntity>(new EMPDbContext(this._ConnString)))
            {
                //var repos = GetRepository<TEntity>();
                repos.Update(model);
                var result = repos.SaveChanges() > 0;
                return result;
            }
        }


        // generic Delete method
        void Delete<TEntity>(Expression<Func<TEntity, bool>> filter) where TEntity : class , new()
        {
            using (var repos = new Repository<EMPDbContext, TEntity>(new EMPDbContext(this._ConnString)))
            {
                //var repos = GetRepository<TEntity>();
                //repos.Delete(filter);
                var modelToDelete = repos.Get(filter);

                foreach (var entry in modelToDelete)
                {
                    if (entry is FB.Data.Models.IRecordState)
                    {
                        ((FB.Data.Models.IRecordState)entry).RecordState = FB.Enums.RecordState.Deleted;
                    }
                }

                repos.SaveChanges();
            }
        }


        #endregion
        */

        public EmployeeInfoUnit GetEmployeeInfoUnit()
        {
            return new EmployeeInfoUnit(new EMPDbContext(this._ConnString));
        }


        public EmployeeInfoService GetEmployeeInfoService()
        {
            return new EmployeeInfoService(GetEmployeeInfoUnit());
        }

    }
}
